﻿using Microsoft.Extensions.Configuration;
using RabbitMQ.Client;
using System;
using System.Collections.Generic;

namespace QQZiFramework.MQ
{
    public class RabbitMQConnectShareManage
    {
        public class ConnectChannelInfo
        {
            public IConnection connection;
            public int channelCount
            {
                get
                {
                    return models.Count;
                }
            }
            public int Index;
            public List<IModel> models = new List<IModel>();

            internal IModel CreateChannel()
            {
                IModel m = connection.CreateModel();
                models.Add(m);
                return m;
            }

            internal void ReleaseChannel(IModel channel)
            {
                this.models.Remove(channel);
                channel.Dispose();
                channel = null;
            }
        }

        private static List<ConnectChannelInfo> connectInfoList;

        public static readonly int Size = 1;

        static ConnectionFactory connectionFactory;

        private static object lockObj = new object();

        static RabbitMQConnectShareManage()
        {
            connectInfoList = new List<ConnectChannelInfo>();
            for (var i = 0; i < Size; i++)
            {
                connectInfoList.Add(new ConnectChannelInfo());
            }

        }

        public static ConnectChannelInfo GetConnection()
        {
            DBContext globalContext = new DBContext();
            int minCountIndex = 0;
            int minValue = 0;
            //找绑定channel最小的conn
            for (var i = 0; i < connectInfoList.Count; i++)
            {
                if (connectInfoList[i].channelCount == 0)
                {
                    minCountIndex = i; break;
                }
                if (connectInfoList[i].channelCount < minValue)
                {
                    minCountIndex = i;
                    minValue = connectInfoList[i].channelCount;
                }
            }
            //如果超过1K，这新开连接
            if (minValue > 1000)
            {
                minCountIndex = connectInfoList.Count;
                connectInfoList.Add(new ConnectChannelInfo());
            }
            ConnectChannelInfo conn = connectInfoList[minCountIndex];
            if (conn.connection == null)
            {
                lock (lockObj)
                {
                    if (connectionFactory == null)
                    {
                        var Configuration = DBContext.ServiceProvider.GetService(typeof(IConfiguration)) as IConfiguration;
                        var configItem = Configuration.GetSection("RabbitMQ");
                        var hostName = configItem["HostName"];
                        var port = configItem["Port"];
                        var userName = configItem["UserName"];
                        var password = configItem["Password"];
                        bool AutoAck = false;
                        if (configItem["AutoAck"] != null)
                            AutoAck = Convert.ToBoolean(configItem["AutoAck"]);
                        if (string.IsNullOrEmpty(hostName)) throw new ArgumentNullException("请在appsetting.json啊配置RabbitMQ:HostName");
                        if (string.IsNullOrEmpty(port)) throw new ArgumentNullException("请在appsetting.json啊配置RabbitMQ:Port");
                        if (string.IsNullOrEmpty(userName)) throw new ArgumentNullException("请在appsetting.json啊配置RabbitMQ:UserName");
                        if (string.IsNullOrEmpty(password)) throw new ArgumentNullException("请在appsetting.json啊配置RabbitMQ:Password");
                        if(userName.IndexOf('/') >-1 || userName.IndexOf('@')>-1 || userName.IndexOf(':')>-1) userName = System.Web.HttpUtility.UrlDecode(userName);
                        if(password.IndexOf('/') >-1 || password.IndexOf('@')>-1 || password.IndexOf(':')>-1) password = System.Web.HttpUtility.UrlDecode(password);
                        //var queues = configItem.GetSection("Queues");
                        //if (queues != null)
                        //{
                        //    if (queues["BasicQos"] != null) BasicQos = Convert.ToUInt16(queues["BasicQos"]);
                        //    if (queues["Durable"] != null) Durable = Convert.ToBoolean(queues["Durable"]);
                        //}
                        var connectionString = $"amqp://{userName}:{password}@{hostName}:{port}/";
                        globalContext.LogDebug("准备初始" + connectInfoList.Count + "个rabbitmq连接..."+ connectionString,"RabbitMQ");
                        connectionFactory = new ConnectionFactory { Uri = new Uri(connectionString) };
                        
                        foreach (var c in connectInfoList)
                        {                            
                            if (c.connection ==null) c.connection= connectionFactory.CreateConnection();
                        }
                        globalContext.LogDebug("初始" + connectInfoList.Count + "个rabbitmq连接完成","RabbitMQ");
                    }
                    if (conn.connection == null)
                    {
                        globalContext.LogDebug("创建连接...","RabbitMQ");
                        conn.connection = connectionFactory.CreateConnection();
                        globalContext.LogDebug("创建连接成功","RabbitMQ");
                    }
                }
            }
            conn.Index = minCountIndex;
            conn.connection.ConnectionShutdown += (s, e) =>
            {
                conn.connection = null;
            };
            globalContext.LogDebug("使用Conn[:" + minCountIndex+"]","RabbitMQ");

            return conn;

        }

         
    }
}
